package com.airlines.crewassignment.service.linkline.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.airlines.base.service.base.impl.BaseServiceImpl;
import com.airlines.common.CloneUtils;
import com.airlines.common.DateTimeRangeUtil;
import com.airlines.common.TimeUtil;
import com.airlines.crewassignment.constant.LinkLineConstant;
import com.airlines.crewassignment.dao.FlightInfoMapper;
import com.airlines.crewassignment.dao.linkline.TaskLoopFlightFactMapper;
import com.airlines.crewassignment.domain.DateTimeRange;
import com.airlines.crewassignment.domain.FlightInfo;
import com.airlines.crewassignment.domain.LinkLine;
import com.airlines.crewassignment.entity.linkline.TaskLoop;
import com.airlines.crewassignment.entity.linkline.TaskLoopDay;
import com.airlines.crewassignment.entity.linkline.TaskLoopFlight;
import com.airlines.crewassignment.entity.linkline.TaskLoopFlightFact;
import com.airlines.crewassignment.service.linkline.FullCalendarService;
import com.airlines.crewassignment.service.linkline.PositionService;
import com.airlines.crewassignment.service.linkline.TaskLoopFlightFactService;
import com.airlines.crewassignment.service.linkline.TaskLoopFlightService;
import com.airlines.crewassignment.service.linkline.TaskLoopService;

/**
 * @author xxxx
 * @date 2018年6月22日 
 * @description
 */
@Service
public class TaskLoopFlightFactServiceImpl extends BaseServiceImpl<TaskLoopFlightFact, Integer> implements TaskLoopFlightFactService{
	@Autowired
	private TaskLoopFlightFactMapper taskLoopFlightFactMapper;
	@Autowired
	private TaskLoopService taskLoopService;
	@Autowired
	private FlightInfoMapper flightInfoMapper;
	@Autowired
	private TaskLoopFlightService taskLoopFlightService;

	@Autowired
	private FullCalendarService fullCalendarService;
	
	@Autowired
	private PositionService positionService;
	
	
	@Autowired
	@Override
	public void setBaseMapper() {
		super.setBaseMapper(taskLoopFlightFactMapper);
	}
	@Override
	public TaskLoopFlightFact getTaskLoopFlightFact(String dutyCode, int flightId) {
		return taskLoopFlightFactMapper.getTaskLoopFlightFact(dutyCode, flightId) ;
	}
	@Override
	public List<TaskLoopFlightFact> listTaskLoopFlightFactByFlightId(String dutyCode, int flightId) {
		return taskLoopFlightFactMapper.listTaskLoopFlightFactByFlightId(dutyCode, flightId);
	}
	@Override
	public Set<String> getTaskLoopFactSet(List<TaskLoopFlightFact> loopList) {
		Set<String> set = new HashSet<>();
		for(TaskLoopFlightFact t : loopList){
			if(StringUtils.isNoneBlank(t.getTaskLoopFact())){
				set.add(t.getTaskLoopFact());
			}
		}
		return set;
	}
	@Override
	public String buildTaskLoopFact() {
		return taskLoopFlightFactMapper.buildTaskLoopFact();
	}
	@Override
	public int saveOrUpdateTaskLoopFact(String dutyCode,Date flightDate, int flightId, String taskLoopFact) {
		TaskLoopFlightFact t = this.getTaskLoopFlightFact(dutyCode, flightId);
		if(t == null){
			TaskLoopFlightFact nt = new TaskLoopFlightFact();
			nt.setFlightDate(flightDate);
			nt.setFlightId(flightId);
			nt.setModuleFlag(dutyCode);
			nt.setTaskLoopFact(taskLoopFact);
			return this.saveSelective(nt);
		}else{
			t.setTaskLoopFact(taskLoopFact);
			return taskLoopFlightFactMapper.updateTaskLoopFact(dutyCode, flightId, taskLoopFact);
		}
		
	}
	@Override
	public int getRemainDutyDurationOfLoopPlan(LinkLine l, Date endFlightDate) {
		List<FlightInfo> list =l.getFlightInfoSameTaskLoopList();
		DateTime start = new DateTime(l.getFlightDate()).plusDays(1);
		DateTime end  = new DateTime(endFlightDate);
		
		int remainDutyDuration = 0; 
		for(DateTime temp = start; !temp.isAfter(end) ;temp = temp.plusDays(1)){
			List<FlightInfo> nextDayList = new ArrayList<>();
			for(FlightInfo f : list){
				if(f.getFlightDate().equals(temp.toDate())){
					nextDayList.add(f);
				}
			}
			
			if(CollectionUtils.isNotEmpty(nextDayList)){
				Date td  = nextDayList.get(0).getStd();
				Date ta  = nextDayList.get(nextDayList.size()-1).getSta();
				DateTimeRange  dtr = new DateTimeRange(td,ta);	
				remainDutyDuration += dtr.getDuration();
				remainDutyDuration += LinkLineConstant.DUTY_DURATION_ADD ;
			}
			
		}
		return remainDutyDuration;
	}
	@Override
	public int getRemainFlyDurationOfLoopPlan(LinkLine l, Date endFlightDate) {
		List<FlightInfo> list =l.getFlightInfoSameTaskLoopList();
		DateTime start = new DateTime(l.getFlightDate()).plusDays(1);
		DateTime end  = new DateTime(endFlightDate);
		
		int remainFlyDuration = 0; 
		for(DateTime temp = start; !temp.isAfter(end) ;temp = temp.plusDays(1)){
			for(FlightInfo f : list){
				if(f.getFlightDate().equals(temp.toDate())){
					Date std  = f.getStd();
					Date sta = f.getSta();	
					DateTimeRange  dtr = new DateTimeRange(std,sta);	
					remainFlyDuration += dtr.getDuration();
				}
			}			
		}
		return remainFlyDuration;
	}
	@Override
	public int updateRestTime(String dutyCode, int flightId, Integer restTime) {
		if(restTime == null){
			restTime = 0;
		}
		return taskLoopFlightFactMapper.updateRestTime(dutyCode, flightId, restTime);
	}
	
	//@Transactional(transactionManager=PrimaryDataSourceConfig.TRANSACTION_MANAGER)
	@Override
	public void autoTaskLoopFact(String dutyCode,Date flightDateStart, Date flightDateEnd,int[] taskLoopId) {
		flightDateEnd = TimeUtil.getDateDayEndTime(flightDateEnd);
		//判断该日期范围内的航班能否自动组环组连线
		boolean flightDateCk = fullCalendarService.flightDateCk(flightDateStart, flightDateEnd);
		if(!flightDateCk){
			return;
		}
		
		DateTimeRange dtr = new DateTimeRange(flightDateStart,flightDateEnd);
		//1.清除该日期范围内的所有的航班的连线信息、排班信息、任务环信息
//		if(StringUtils.equals(dutyCode, CrewConstant.DUTY_F)){
//			clearBeforeautoTaskLoopFact(CrewConstant.DUTY_F, dtr);
//		}
//		if(StringUtils.equals(dutyCode, CrewConstant.DUTY_C) || LinkLineConstant.LINKLINE_SYNCHRO_F_TO_CA){
//			clearBeforeautoTaskLoopFact(CrewConstant.DUTY_C, dtr);
//		}
//		if(StringUtils.equals(dutyCode, CrewConstant.DUTY_A) || LinkLineConstant.LINKLINE_SYNCHRO_F_TO_CA){
//			clearBeforeautoTaskLoopFact(CrewConstant.DUTY_A, dtr);
//		}
		
		//2.查询任务环定义信息
		TaskLoop query = new TaskLoop();
		query.setDutyCode(dutyCode);
		List<TaskLoop> taskLoopList = taskLoopService.listData(query);
		List<TaskLoop> taskLoopListAll = new ArrayList<>(); //任务环信息全的列表
		for(TaskLoop temp : taskLoopList){
			DateTimeRange dtrt = new DateTimeRange(temp.getStartDate(),temp.getEndDate());
			if(DateTimeRangeUtil.isIntersection(dtr, dtrt)){
				int tempId = temp.getId();
				boolean idFlag = false;
				for(int taskLoopIdTemp : taskLoopId){
					if(tempId == taskLoopIdTemp){
						idFlag = true;
					}
				}
				if(idFlag){
					TaskLoop t = taskLoopService.getTaskLoopAll(temp.getId());
					taskLoopListAll.add(t);
				}
			}
		}
			
		//3.查询所有航班
		List<FlightInfo> flightInfoList = flightInfoMapper.listFlightInfoByDateTimeRange(dtr.getStart(), dtr.getEnd());
		
		//4.初始化构造任务环实例，将航班匹配到环的第一个航班定义中
		List<TaskLoop> taskLoopListFact = new ArrayList<>(); //任务环信息全的列表
		for(FlightInfo f : flightInfoList){
			for(TaskLoop t : taskLoopListAll){
				List<TaskLoopFlight> tlfList = this.getTaskLoopFlight(t);
				TaskLoopFlight tlfFrist = tlfList.get(0);
				if(taskLoopFlightService.matching(t,tlfFrist, f)){
					TaskLoop tFact = CloneUtils.clone(t);
					this.getTaskLoopFlight(tFact).get(0).setFlightInfo(f);
					taskLoopListFact.add(tFact);
				}
			}
		}
		
		//5.根据第一步得到的任务环实例，将剩余航班匹配到第2到最后一个航班定义中
		for(TaskLoop t : taskLoopListFact){
			int indexMax = this.getTaskLoopFlight(t).size();
			for(int i = 1; i < indexMax ;i ++){
				matching(t, flightInfoList, i);
			}
		}
		
		//6.将每个任务环实例中的航班，组成具体的航班任务环和连线
		for(TaskLoop t : taskLoopListFact){
			//1.判断任务环航班是否是完整的，没有缺失的，如果有缺失，则不组环，不组连线
			List<TaskLoopFlight> tlfList = this.getTaskLoopFlight(t);
			if(tlfList ==null || tlfList.size()==0){
				continue;
			}

			boolean flagNull = false;
			for(TaskLoopFlight tlf : tlfList){
				if(tlf.getFlightInfo() == null){
					flagNull = true;
				}
			}
			if(flagNull){
				continue;
			}
			
			
			//2.1移除每个航班的连线
			Set<String> flightDateAndCrewLinkLineNoSet = new HashSet<>();
			for(TaskLoopFlight tlfDelete : tlfList){
				FlightInfo flightDelete = tlfDelete.getFlightInfo();
				//构造连线
				Integer crewLinkLineNoFlightInfo = fullCalendarService.getCrewLinkLineNo(flightDelete, dutyCode);
				if(crewLinkLineNoFlightInfo != null){
					fullCalendarService.removeFlightFromLinkLine(flightDelete.getFlightId(), dutyCode);
					flightDateAndCrewLinkLineNoSet.add(TimeUtil.transDate(flightDelete.getFlightDate())+"----"+crewLinkLineNoFlightInfo);
				}
			}
			//2.2.删除任务环连线上的其他航班
			Set<String> flightDateAndCrewLinkLineNoSetOther = new HashSet<>();
			for(String flightDateAndCrewLinkLineNo : flightDateAndCrewLinkLineNoSet){
				String[] array = flightDateAndCrewLinkLineNo.split("----");
				Date flightDateTemp = TimeUtil.getDateByYyyyMM(array[0]);
				Integer crewLinkLineNoTemp = Integer.valueOf(array[1]);

				List<FlightInfo> sameTaskFlightList =  fullCalendarService.listFlightBySameTaskLoopFact(dutyCode, flightDateTemp, crewLinkLineNoTemp);
				if(sameTaskFlightList != null){
					for(FlightInfo sameFlight : sameTaskFlightList){
						Integer crewLinkLineNoFlightInfo = fullCalendarService.getCrewLinkLineNo(sameFlight, dutyCode);
						if(crewLinkLineNoFlightInfo != null){
							fullCalendarService.removeFlightFromLinkLine(sameFlight.getFlightId(), dutyCode);
							flightDateAndCrewLinkLineNoSetOther.add(TimeUtil.transDate(sameFlight.getFlightDate())+"----"+crewLinkLineNoFlightInfo);
						}
					}
				}
				
			}
			//2.3 删除连线
			flightDateAndCrewLinkLineNoSet.addAll(flightDateAndCrewLinkLineNoSetOther);
			for(String flightDateAndCrewLinkLineNo : flightDateAndCrewLinkLineNoSet){
				String[] array = flightDateAndCrewLinkLineNo.split("----");
				Date flightDateTemp = TimeUtil.getDateByYyyyMM(array[0]);
				Integer crewLinkLineNoTemp = Integer.valueOf(array[1]);
				
				fullCalendarService.deleteLinkLine(dutyCode, flightDateTemp, crewLinkLineNoTemp);
			}
			
			
			
			//3.处理第一个航班
			TaskLoopFlight tlfFrist = tlfList.get(0);
			FlightInfo flightInfoFrist = tlfFrist.getFlightInfo();
			Date flightDate = flightInfoFrist.getFlightDate();
			int crewLinkLineNo = fullCalendarService.getNewCrewLinkLineNo(dutyCode,flightDate);
			LinkLine l = fullCalendarService.getOrInitLinkLine(flightInfoFrist.getFlightId(), dutyCode, flightDate, crewLinkLineNo);
			fullCalendarService.addFlightToLinkLine(flightInfoFrist.getFlightId(), dutyCode, l.getFlightDate(), l.getCrewLinkLineNo(),l.getTaskLoopFact());
			flightInfoFrist.getFlightId();
			tlfFrist.getArrivalAirportRestTime();
			this.updateRestTime(dutyCode, flightInfoFrist.getFlightId(), tlfFrist.getArrivalAirportRestTime());
			this.updateBadRoute(dutyCode, flightInfoFrist.getFlightId(),t.getBadRoute());
			this.updateMinMale(dutyCode, flightInfoFrist.getFlightId(), t.getMinMale());
			this.updateInternationalTimeZoneMore6(dutyCode,  flightInfoFrist.getFlightId(),t.getInternationalTimeZoneMore6());
			this.updateCrewTypeId(dutyCode, flightInfoFrist.getFlightId(), Integer.valueOf(t.getCrewNumberType()));
			positionService.initPositionByCrewType(dutyCode, l.getFlightDate(),  l.getCrewLinkLineNo(),Integer.valueOf(t.getCrewNumberType()));
			//4.处理第二个到第N个航班
			for(int i=1;i<tlfList.size();i++){
				FlightInfo flightInfoNext =  tlfList.get(i).getFlightInfo();
				LinkLine lNext = fullCalendarService.getOrInitLinkLine(flightInfoNext.getFlightId(), dutyCode, flightDate, crewLinkLineNo);
				fullCalendarService.addFlightToLinkLine(flightInfoNext.getFlightId(), dutyCode, lNext.getFlightDate(), lNext.getCrewLinkLineNo(),lNext.getTaskLoopFact());
				this.updateRestTime(dutyCode, flightInfoNext.getFlightId(),  tlfList.get(i).getArrivalAirportRestTime());
				this.updateBadRoute(dutyCode, flightInfoNext.getFlightId(),t.getBadRoute());
				this.updateMinMale(dutyCode,  flightInfoNext.getFlightId(), t.getMinMale());
				this.updateInternationalTimeZoneMore6(dutyCode,  flightInfoNext.getFlightId(),t.getInternationalTimeZoneMore6());
				this.updateCrewTypeId(dutyCode, flightInfoNext.getFlightId(), Integer.valueOf(t.getCrewNumberType()));
				positionService.initPositionByCrewType(dutyCode, l.getFlightDate(),  l.getCrewLinkLineNo(),Integer.valueOf(t.getCrewNumberType()));
			}
		}
	}

	/**
	 * 
	 * 更新某个航班为国际航班且差6时区以上
	 * @param dutyCode
	 * @param flightId
	 * @param internationalTimeZoneMore6
	 * @return
	 */
	@Override
	public int updateInternationalTimeZoneMore6(String dutyCode, Integer flightId,
			Boolean internationalTimeZoneMore6) {
		if(internationalTimeZoneMore6 == null){
			internationalTimeZoneMore6 = false;
		}
		return taskLoopFlightFactMapper.updateInternationalTimeZoneMore6(dutyCode, flightId, internationalTimeZoneMore6);
	}
	/**
	 * 跟新某个航班为差航班
	 * @param dutyCode
	 * @param flightId
	 * @param badRoute
	 */
	@Override
	public int updateBadRoute(String dutyCode, Integer flightId, Boolean badRoute) {
		if(badRoute == null){
			badRoute = false;
		}
		return taskLoopFlightFactMapper.updateBadRoute(dutyCode, flightId, badRoute);
	}
	private List<TaskLoopFlight> getTaskLoopFlight(TaskLoop taskLoop){
		List<TaskLoopFlight> taskLoopFlightList = new ArrayList<>(); //任务环航班定义列表
		List<TaskLoopDay> dayList = taskLoop.getDayList();
		for(TaskLoopDay day : dayList){
			taskLoopFlightList.addAll(day.getFlightList());
		}
		return taskLoopFlightList;
	}
	
	/**
	 * 根据任务环实例+航班列表，匹配到该任务环实例的具体任务航班中
	 * @param taskLoop
	 * @param flightInfoList
	 * @param index
	 */
	private void matching(TaskLoop taskLoop,List<FlightInfo> flightInfoList,int index){
		List<TaskLoopFlight> tlfList = this.getTaskLoopFlight(taskLoop);
		if(CollectionUtils.isEmpty(tlfList)){
			return;
		}
		if(index ==0){
			return;
		}
		if(index >= tlfList.size()){
			return;
		}
		
		TaskLoopFlight tlfLast = tlfList.get(index-1);
		TaskLoopFlight tlfThis = tlfList.get(index);
		int tlfDayDiff = tlfThis.getLoopDay() - tlfLast.getLoopDay(); //本航班定义与上一个航班定义的日期的差值
		
		for(FlightInfo f : flightInfoList){
			boolean matchFlag = taskLoopFlightService.matching(taskLoop,tlfThis, f);
			if(matchFlag){
				FlightInfo fLast = tlfLast.getFlightInfo();
				if(fLast == null || f==null){
					continue;
				}
				Duration duration = new Duration(new DateTime(fLast.getFlightDate()), new DateTime(f.getFlightDate()));
				int flightDayDiff = (int) duration.getStandardDays();
				if(tlfDayDiff == flightDayDiff){
					tlfThis.setFlightInfo(f);
				}
			}

		}
	}
	
	/**
	 * 自动组环之前，清除所有数据
	 * @param dutyCode
	 * @param dtr
	 */
/*	private void clearBeforeautoTaskLoopFact(String dutyCode,DateTimeRange dtr ){
		flightInfoMapper.updateCrewLinkLineNoNull(dutyCode, dtr);
		taskLoopFlightFactMapper.deleteByFlightDate(dutyCode, dtr);
		positionMapper.deleteByFlightDateRange(dutyCode, dtr);
		linkLineMapper.deleteMaxCrewLinkLine(dutyCode, dtr);
		flightCrewLinkLineNoMapper.deleteByFlightDateRange(dutyCode, dtr);
		
		
		if(StringUtils.equals(dutyCode, CrewConstant.DUTY_F)){
			linkLineMapper.deleteByFlightDateRange(dtr);
			linkLineFMapper.deleteByFlightDateRange(dtr);
		}
		if(StringUtils.equals(dutyCode, CrewConstant.DUTY_C)){
			linkLineCMapper.deleteByFlightDateRange(dtr);
		}
		if(StringUtils.equals(dutyCode, CrewConstant.DUTY_A)){
			linkLineAMapper.deleteByFlightDateRange(dtr);
		}
	}*/
	@Override
	public List<TaskLoopFlightFact> listTaskLoopFlightFactByCrewLinkLine(String dutyCode, Date flightDate,
			int crewLinkLine) {
		return taskLoopFlightFactMapper.listTaskLoopFlightFactByCrewLinkLine(dutyCode, flightDate, crewLinkLine);
	}
	
	@Override
	public List<FlightInfo> flightInfoTaskLoopFlightFactListInit(String dutyCode,List<FlightInfo> list) {
		List<Date> dateList = new ArrayList<>();
		for(FlightInfo f : list){
			dateList.add(f.getFlightDate());
		}
		if(CollectionUtils.isEmpty(dateList)){
			return list;
		}
		Collections.sort(dateList);
		
		Date start = dateList.get(0);
		Date end = dateList.get(dateList.size()-1);
		DateTimeRange dateTimeRange = new DateTimeRange(start,end);
		List<TaskLoopFlightFact> tlffList = taskLoopFlightFactMapper.listTaskLoopFlightFactByDateTimeRange(dateTimeRange);
		for(FlightInfo f : list){
			for(TaskLoopFlightFact tlff : tlffList){
				if(f.getFlightId().equals(tlff.getFlightId())){
					if(StringUtils.isBlank(dutyCode)){
						f.getTaskLoopFlightFactList().add(tlff);
					}else if(StringUtils.equals(tlff.getModuleFlag(),dutyCode)){
						f.getTaskLoopFlightFactList().add(tlff);
					}
				}
			}
		}
		return list;
	}
	@Override
	public int updateMinMale(String dutyCode, Integer flightId, Integer minMale) {
		if(minMale !=null){
			return taskLoopFlightFactMapper.updateMinMale(dutyCode, flightId, minMale);
		}else{
			return 0;
		}
	}
	@Override
	public int updateCrewTypeId(String dutyCode, Integer flightId, Integer crewType) {
		return taskLoopFlightFactMapper.updateCrewTypeId(dutyCode, flightId, crewType);
	}

}
